import { createElement, Fragment, HTMLAttributes, useState, type FC } from 'react';
import classNames from 'classnames';
import { jsx, CSSObject } from '@emotion/react';
import { dropdownMenuDefaultProps } from './defaultProps';
import type { DropdownMenuOptions } from './type';
import { useEnsuredForwardedRef, useUpdateEffect } from 'react-use';
import { useDropdownContext } from './DropdownContext';

export interface DropdownMenuProps extends DropdownMenuOptions, HTMLAttributes<HTMLDivElement> {}

const DropdownMenu: FC<DropdownMenuProps> = (props) => {
  const { className, ui, open, children, forwardedRef, ...dropdownMenuProps } = props;
  const [styles, setStyles] = useState<CSSObject>();
  const [csses, setCsses] = useState<string>();
  const [upward, setUpward] = useState(false);
  const [states, setStates] = useDropdownContext();
  const ensuredForwardRef = useEnsuredForwardedRef<HTMLDivElement | null>(forwardedRef!);

  useUpdateEffect(() => {
    const dropdownEl = ensuredForwardRef.current?.parentElement;
    const isSubMenu = dropdownEl?.classList.value.split(' ').includes('item');
    if (open) {
      setStyles({
        display: 'block !important',
        width: 0,
        height: 0,
        border: 'none !important',
        overflow: 'hidden !important',
      });
      setTimeout(() => {
        const dropdownRect = dropdownEl?.getBoundingClientRect();
        let isUpward = false;
        if (isSubMenu) {
          const spaceAtTheBottom =
            document.body.clientHeight - (dropdownRect?.top || 0) - (ensuredForwardRef.current?.scrollHeight || 0);
          const spaceAtTheTop =
            (dropdownRect?.top || 0) + (dropdownRect?.height || 0) - (ensuredForwardRef.current?.scrollHeight || 0);
          isUpward = states.defaultUpward
            ? spaceAtTheTop > 0 || spaceAtTheTop > spaceAtTheBottom
            : spaceAtTheBottom < 0 && spaceAtTheTop > spaceAtTheBottom;
          setUpward(isUpward);
        } else {
          const spaceAtTheBottom =
            document.body.clientHeight -
            (dropdownRect?.top || 0) -
            (dropdownRect?.height || 0) -
            (ensuredForwardRef.current?.scrollHeight || 0);

          const spaceAtTheTop = (dropdownRect?.top || 0) - (ensuredForwardRef.current?.scrollHeight || 0);

          isUpward = states.defaultUpward
            ? spaceAtTheTop > 0 || spaceAtTheTop > spaceAtTheBottom
            : spaceAtTheBottom < 0 && spaceAtTheTop > spaceAtTheBottom;
          setUpward(isUpward);
          setStates({ ...states, upward: isUpward });
        }
        setCsses(
          classNames(
            { upward: isSubMenu ? isUpward : false },
            'transition',
            'animating',
            'slide',
            isUpward ? 'up' : 'down',
            'in',
          ),
        );
        setStyles({ display: 'block !important', animationDuration: `${states.duration || 0}ms` });
        setTimeout(() => {
          setCsses(classNames({ upward: isSubMenu ? isUpward : false }, 'transition', 'visible'));
          setStyles({ display: 'block !important' });
        }, states.duration);
      });
    } else {
      setCsses(
        classNames(
          { upward: isSubMenu ? upward : false },
          'transition',
          'animating',
          'slide',
          upward ? 'up' : 'down',
          'out',
        ),
      );
      setStyles({ display: 'block !important', animationDuration: `${states.duration || 0}ms` });
      setTimeout(() => {
        setCsses(classNames({ upward: isSubMenu ? upward : false }, 'transition', 'hidden'));
        setStyles(undefined);
      }, states.duration);
    }
  }, [open]);

  return createElement(Fragment, {}, [
    <i key="icon" className="dropdown icon"></i>,
    jsx(
      'div',
      {
        ref: ensuredForwardRef,
        key: 'dropdownMenu',
        className: classNames({ ui }, 'menu', csses, className),
        css: styles,
        tabIndex: -1,
        onClick: (e) => e.stopPropagation(),
        ...dropdownMenuProps,
      },
      children,
    ),
  ]);
};

DropdownMenu.displayName = 'DropdownMenu';
DropdownMenu.defaultProps = dropdownMenuDefaultProps;

export default DropdownMenu;
